using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Drawing.Drawing2D;
using System.Data;
using System.Text;
using System.Windows.Forms;
using System.Runtime.Serialization;
using System.Security.Permissions;
using System.Reflection;

namespace Skywave.Windows.Forms.RuntimeDesign
{
    [Serializable()]
    public partial class ControlEditor : UserControl, System.Runtime.Serialization.ISerializable
    {
        bool isMouseOnChildControl = false;

        public ControlEditor()
        {
            InitializeComponent();

            SetChildBounds();
        }

        private void SetChildBounds()
        {
            panelControl.Left = mEdgeSize;
            panelControl.Top = mEdgeSize;
            panelControl.Width = this.Width - 2 * mEdgeSize;
            panelControl.Height = this.Height - 2 * mEdgeSize;

            panelBottomLeft.Size = new Size(mEdgeSize, mEdgeSize);
            panelBottomMiddle.Size = new Size(mEdgeSize, mEdgeSize);
            panelBottomRight.Size = new Size(mEdgeSize, mEdgeSize);
            panelTopLeft.Size = new Size(mEdgeSize, mEdgeSize);
            panelTopRight.Size = new Size(mEdgeSize, mEdgeSize);
            panelTopMiddle.Size = new Size(mEdgeSize, mEdgeSize);
            panelMiddleLeft.Size = new Size(mEdgeSize, mEdgeSize);
            panelMiddleRight.Size = new Size(mEdgeSize, mEdgeSize);

            panelBottomLeft.Left = 0;
            panelBottomLeft.Top = this.Height - mEdgeSize;
            panelBottomMiddle.Left = ((this.Width - mEdgeSize) / 2);
            panelBottomMiddle.Top = this.Height - mEdgeSize;
            panelBottomRight.Left = this.Width - mEdgeSize;
            panelBottomRight.Top = this.Height - mEdgeSize;

            panelTopLeft.Left = 0;
            panelTopLeft.Top = 0;
            panelTopMiddle.Left = ((this.Width - mEdgeSize) / 2);
            panelTopMiddle.Top = 0;
            panelTopRight.Left = this.Width - mEdgeSize;
            panelTopRight.Top = 0;

            panelMiddleLeft.Left = 0;
            panelMiddleLeft.Top = ((this.Height - mEdgeSize) / 2);
            panelMiddleRight.Left = this.Width - mEdgeSize;
            panelMiddleRight.Top = ((this.Height - mEdgeSize) / 2);

            panelMove.Left = this.Width - mEdgeSize - panelMove.Width;
            panelMove.Top = mEdgeSize;

            panelBorder_Left.Left = mEdgeSize - mBorderWidth;
            panelBorder_Left.Top = mEdgeSize - mBorderWidth;
            panelBorder_Left.Width = mBorderWidth;
            panelBorder_Left.Height = this.Height - 2 * mEdgeSize + 2 * mBorderWidth;

            panelBorder_Top.Left = mEdgeSize - mBorderWidth;
            panelBorder_Top.Top = mEdgeSize - mBorderWidth;
            panelBorder_Top.Width = this.Width - 2 * mEdgeSize + 2 * mBorderWidth;
            panelBorder_Top.Height = mBorderWidth;

            panelBorder_Right.Left = mEdgeSize + this.Width - 2 * mEdgeSize;
            panelBorder_Right.Top = mEdgeSize - mBorderWidth;
            panelBorder_Right.Width = mBorderWidth;
            panelBorder_Right.Height = this.Height - 2 * mEdgeSize + 2 * mBorderWidth;

            panelBorder_Bottom.Left = mEdgeSize - mBorderWidth;
            panelBorder_Bottom.Top = mEdgeSize + this.Height - 2 * mEdgeSize;
            panelBorder_Bottom.Width = this.Width - 2 * mEdgeSize + 2 * mBorderWidth;
            panelBorder_Bottom.Height = mBorderWidth;
        }

        private int mBorderWidth = 1;
        public int BorderWidth
        {
            get { return mBorderWidth; }
            set { mBorderWidth = value; }
        }

        private Color mBorderColorFocused = Color.Blue;
        public Color BorderColorFocused
        {
            get { return mBorderColorFocused; }
            set { mBorderColorFocused = value; }
        }

        private Color mBorderColorMouseOver = Color.LightGreen;
        public Color BorderColorMouseOver
        {
            get { return mBorderColorMouseOver; }
            set { mBorderColorMouseOver = value; }
        }

        private int mEdgeSize = 7;
        public int EdgeSize
        {
            get { return mEdgeSize; }
            set { mEdgeSize = value; }
        }

        private Control mChildControl;
        public Control ChildControl
        {
            get { return mChildControl; }
            set
            {
                mChildControl = value;
                if (mChildControl != null)
                {
                    mChildControl.Dock = DockStyle.Fill;
                    mChildControl.Enter += new EventHandler(mChildControl_Enter);
                    mChildControl.Leave += new EventHandler(mChildControl_Leave);
                    mChildControl.MouseLeave += new EventHandler(mChildControl_MouseLeave);
                    mChildControl.MouseEnter += new EventHandler(mChildControl_MouseEnter);
                    //mChildControl.KeyPress += new KeyPressEventHandler(Control_KeyPress);
                    //mChildControl.PreviewKeyDown += new PreviewKeyDownEventHandler(Control_PreviewKeyDown);
                    if (mChildControl is TextBox)
                    {
                        ((TextBox)mChildControl).Multiline = true;
                    }
                    this.panelControl.Controls.Clear();
                    this.panelControl.Controls.Add(mChildControl);
                }
                else
                {
                    this.panelControl.Controls.Clear();
                }
            }
        }

        void mChildControl_MouseEnter(object sender, EventArgs e)
        {
            bool containsF = (this.Focused || (mChildControl != null && mChildControl.Focused));
            if (!containsF && !isMouseOnChildControl)
            {
                isMouseOnChildControl = true;
                this.Invalidate();
            }
        }

        void mChildControl_MouseLeave(object sender, EventArgs e)
        {
            bool containsF = (this.Focused || (mChildControl != null && mChildControl.Focused));
            if (!containsF && isMouseOnChildControl)
            {
                isMouseOnChildControl = false;
                this.Invalidate();
            }
        }

        void mChildControl_Leave(object sender, EventArgs e)
        {
            this.Invalidate();
        }

        void mChildControl_Enter(object sender, EventArgs e)
        {
            this.Invalidate();
        }

        private bool mProvideFunctions;
        public bool ProvideFunctions
        {
            get { return mProvideFunctions; }
            set { mProvideFunctions = value; this.Invalidate(); }
        }

        private void ControlEditor_Paint(object sender, PaintEventArgs e)
        {
            System.Drawing.Drawing2D.GraphicsPath resaultPath = new System.Drawing.Drawing2D.GraphicsPath();
            bool showBorder = false;
            bool provideFunctions = mProvideFunctions; //(this.Focused || (mChildControl != null && mChildControl.Focused));
            if (provideFunctions)
            {
                if (mAllowTopLeftResize) resaultPath.AddRectangle(panelTopLeft.Bounds);
                if (mAllowTopRightResize) resaultPath.AddRectangle(panelTopRight.Bounds);
                if (mAllowTopMiddleResize) resaultPath.AddRectangle(panelTopMiddle.Bounds);
                if (mAllowBottomLeftResize) resaultPath.AddRectangle(panelBottomLeft.Bounds);
                if (mAllowBottomRightResize) resaultPath.AddRectangle(panelBottomRight.Bounds);
                if (mAllowBottomMiddleResize) resaultPath.AddRectangle(panelBottomMiddle.Bounds);
                if (mAllowMiddleLeftResize) resaultPath.AddRectangle(panelMiddleLeft.Bounds);
                if (mAllowMiddleRightResize) resaultPath.AddRectangle(panelMiddleRight.Bounds);
                showBorder = true;
            }
            else if (isMouseOnChildControl)
            {
                showBorder = true;
            }
            panelMove.Visible = provideFunctions & mAllowMove;
            panelBottomLeft.Visible = provideFunctions & mAllowBottomLeftResize;
            panelBottomMiddle.Visible = provideFunctions & mAllowBottomMiddleResize;
            panelBottomRight.Visible = provideFunctions & mAllowBottomRightResize;
            panelTopLeft.Visible = provideFunctions & mAllowTopLeftResize;
            panelTopMiddle.Visible = provideFunctions & mAllowTopMiddleResize;
            panelTopRight.Visible = provideFunctions & mAllowTopRightResize;
            panelMiddleLeft.Visible = provideFunctions & mAllowMiddleLeftResize;
            panelMiddleRight.Visible = provideFunctions & mAllowMiddleRightResize;

            panelBorder_Bottom.Visible = showBorder;
            panelBorder_Left.Visible = showBorder;
            panelBorder_Right.Visible = showBorder;
            panelBorder_Top.Visible = showBorder;
            if (showBorder)
            {
                Color borderColor = (provideFunctions) ? mBorderColorFocused : mBorderColorMouseOver;
                resaultPath.AddRectangle(panelBorder_Bottom.Bounds);
                resaultPath.AddRectangle(panelBorder_Left.Bounds);
                resaultPath.AddRectangle(panelBorder_Right.Bounds);
                resaultPath.AddRectangle(panelBorder_Top.Bounds);
                panelBorder_Bottom.BackColor = borderColor;
                panelBorder_Left.BackColor = borderColor;
                panelBorder_Right.BackColor = borderColor;
                panelBorder_Top.BackColor = borderColor;
            }
            resaultPath.AddRectangle(panelControl.Bounds);
            System.Drawing.Region resault = new Region(resaultPath);
            this.Region = resault;
        }

        private void panelTopLeft_MouseMove(object sender, MouseEventArgs e)
        {
            if (((e.Button & MouseButtons.Left) == MouseButtons.Left))
            {
                this.Left += e.X;
                this.Width -= e.X;
                this.Top += e.Y;
                this.Height -= e.Y;
                panelControl.Invalidate();
            }
        }

        private void panelTopMiddle_MouseMove(object sender, MouseEventArgs e)
        {
            if (((e.Button & MouseButtons.Left) == MouseButtons.Left))
            {
                this.Top += e.Y;
                this.Height -= e.Y;
                panelControl.Invalidate();
            }
        }

        private void panelTopRight_MouseMove(object sender, MouseEventArgs e)
        {
            if (((e.Button & MouseButtons.Left) == MouseButtons.Left))
            {
                this.Width += e.X;
                this.Top += e.Y;
                this.Height -= e.Y;
                panelControl.Invalidate();
            }
        }

        private void panelMiddleLeft_MouseMove(object sender, MouseEventArgs e)
        {
            if (((e.Button & MouseButtons.Left) == MouseButtons.Left))
            {
                this.Left += e.X;
                this.Width -= e.X;
                panelControl.Invalidate();
            }
        }

        private void panelMiddleRight_MouseMove(object sender, MouseEventArgs e)
        {
            if (((e.Button & MouseButtons.Left) == MouseButtons.Left))
            {
                this.Width += e.X;
                panelControl.Invalidate();
            }
        }

        private void panelBottomLeft_MouseMove(object sender, MouseEventArgs e)
        {
            if (((e.Button & MouseButtons.Left) == MouseButtons.Left))
            {
                this.Left += e.X;
                this.Width -= e.X;
                this.Height += e.Y;
                panelControl.Invalidate();
            }
        }

        private void panelBottomMiddle_MouseMove(object sender, MouseEventArgs e)
        {
            if (((e.Button & MouseButtons.Left) == MouseButtons.Left))
            {
                this.Height += e.Y;
                panelControl.Invalidate();
            }
        }

        private void panelBottomRight_MouseMove(object sender, MouseEventArgs e)
        {
            if ((e.Button & MouseButtons.Left) == MouseButtons.Left)
            {
                this.Height += e.Y;
                this.Width += e.X;
                panelControl.Invalidate();
            }
        }

        private void panelMove_MouseMove(object sender, MouseEventArgs e)
        {
            if (((e.Button & MouseButtons.Left) == MouseButtons.Left))
            {
                this.Left += e.X;
                this.Top += e.Y;
                panelControl.Invalidate();
            }
        }

        private void ControlEditor_Enter(object sender, EventArgs e)
        {
            isMouseOnChildControl = false;
            this.Invalidate();
        }

        private void ControlEditor_Leave(object sender, EventArgs e)
        {
            this.Invalidate();
        }

        private bool mAllowTopLeftResize = true;
        public bool AllowTopLeftResize
        {
            get { return mAllowTopLeftResize; }
            set { mAllowTopLeftResize = value; }
        }

        private bool mAllowTopMiddleResize = true;
        public bool AllowTopMiddleResize
        {
            get { return mAllowTopMiddleResize; }
            set { mAllowTopMiddleResize = value; }
        }

        private bool mAllowTopRightResize = true;
        public bool AllowTopRightResize
        {
            get { return mAllowTopRightResize; }
            set { mAllowTopRightResize = value; }
        }

        private bool mAllowBottomLeftResize = true;
        public bool AllowBottomLeftResize
        {
            get { return mAllowBottomLeftResize; }
            set { mAllowBottomLeftResize = value; }
        }

        private bool mAllowBottomMiddleResize = true;
        public bool AllowBottomMiddleResize
        {
            get { return mAllowBottomMiddleResize; }
            set { mAllowBottomMiddleResize = value; }
        }

        private bool mAllowBottomRightResize = true;
        public bool AllowBottomRightResize
        {
            get { return mAllowBottomRightResize; }
            set { mAllowBottomRightResize = value; }
        }

        private bool mAllowMiddleLeftResize = true;
        public bool AllowMiddleLeftResize
        {
            get { return mAllowMiddleLeftResize; }
            set { mAllowMiddleLeftResize = value; }
        }

        private bool mAllowMiddleRightResize = true;
        public bool AllowMiddleRightResize
        {
            get { return mAllowMiddleRightResize; }
            set { mAllowMiddleRightResize = value; }
        }

        private bool mAllowMove = true;
        public bool AllowMove
        {
            get { return mAllowMove; }
            set { mAllowMove = value; }
        }

        private const int movementSize = 5;
        protected override bool ProcessCmdKey(ref Message msg, Keys keyData)
        {
            int left = 0, top = 0;
            bool keyHandled = false;
            if (this.ProvideFunctions)
            {
                if ((keyData & Keys.Right) == Keys.Right && mAllowMove)
                {
                    left = +1;
                    keyHandled = true;
                }
                else if ((keyData & Keys.Left) == Keys.Left && mAllowMove)
                {
                    left = -1;
                    keyHandled = true;
                }
                else if ((keyData & Keys.Up) == Keys.Up && mAllowMove)
                {
                    top = -1;
                    keyHandled = true;
                }
                else if ((keyData & Keys.Down) == Keys.Down && mAllowMove)
                {
                    top = +1;
                    keyHandled = true;
                }
                if (Control.ModifierKeys != Keys.Control) { left *= movementSize; top *= movementSize; }
                if (keyHandled)
                {
                    this.Left += left;
                    this.Top += top;
                }
            }
            if (!keyHandled)
                return base.ProcessCmdKey(ref msg, keyData);
            else
                return true;
        }

        public Size ChildControlSize
        {
            get { return panelControl.Size; }
        }

        #region ISerializable Members
        public ControlEditor(SerializationInfo si, StreamingContext context)
        {
            InitializeComponent();
            SetChildBounds();
            Control ctrlNew;
            Type ctrlType;
            object[] indexProps = new object[0];
            ctrlType = (Type)si.GetValue("controlType", typeof(Type));
            ctrlNew = (Control)ctrlType.Assembly.CreateInstance(ctrlType.FullName);
            try
            {
                foreach (PropertyInfo prop in ctrlType.GetProperties())
                {
                    if (prop.CanWrite && prop.PropertyType.IsSerializable)
                        prop.SetValue(ctrlNew, si.GetValue(prop.Name, prop.PropertyType), indexProps);
                }
                this.Location = (Point)si.GetValue("myLocation", typeof(Point));
                this.Size = (Size)si.GetValue("mySize", typeof(Size));
            }
            catch (SerializationException ex)
            {
                ex.ToString();
                //Do nothing
                //throw;
            }
            ChildControl = ctrlNew;
        }

        [SecurityPermissionAttribute(SecurityAction.Demand, SerializationFormatter = true)]
        public void GetObjectData(SerializationInfo info, StreamingContext context)
        {
            if (mChildControl != null)
            {
                object[] indexProps = new object[0];
                info.AddValue("controlType", mChildControl.GetType());
                foreach (PropertyInfo prop in mChildControl.GetType().GetProperties())
                {
                    if (prop.CanWrite && prop.PropertyType.IsSerializable)
                        info.AddValue(prop.Name, prop.GetValue(mChildControl, indexProps));
                }
                info.AddValue("myLocation", this.Location);
                info.AddValue("mySize", this.Size);
            }
        }

        #endregion
    }
}
